﻿using System;
using System.Data;

using BizElements.Core.ProviderComponents;

namespace BizElements.Core
{
    /// <summary>Provides values for immutable <see cref="IDbColumn"/> properties.</summary>
    public interface IDbColumnConfiguration
    {
        #region Properties.

        /// <summary>
        /// Gets the <see cref="DbType"/> of the column.
        /// </summary>
        DbType DbType { get; }

        /// <summary>
        /// Gets the value that indicates whether null values are allowed in this column.
        /// </summary>
        bool IsNullable { get; }

        /// <summary>
        /// Gets the value that indicates whether the column automatically increments the value for new rows added to the table.
        /// </summary>
        bool AutoIncrement { get; }

        /// <summary>
        /// Gets the name of the column.
        /// </summary>
        string ColumnName { get; }

        /// <summary>
        /// Gets .NET type of data stored in the column.
        /// </summary>
        Type DataType { get; }

        /// <summary>
        /// Gets the default value for the column when creating new rows.
        /// </summary>
        object DefaultValue { get; }

        /// <summary>
        /// Gets the maximum length of a text column.
        /// Has no effect it it is not a text column.
        /// </summary>
        int MaxLengthIfText { get; }

        /// <summary>
        /// Gets the position of the column in the database table/view.
        /// </summary>
        int Ordinal { get; }

        /// <summary>
        /// Gets the value that indicates whether the column is a part of the primary key.
        /// </summary>
        bool IsPrimaryKeyPart { get; }

        /// <summary>
        /// Gets the value that indicates whether the column is a part of a foreign key.
        /// </summary>
        bool IsForeignKeyPart { get; }

        /// <summary>
        /// Gets the value that indicates whether the column is a part of a unique constraint.
        /// </summary>
        bool IsUniqueConstraintPart { get; }

        /// <summary>
        /// Gets the smallest possible value of this column.
        /// </summary>
        object MinValue { get; }

        /// <summary>
        /// Gets the smallest possible value of this column.
        /// </summary>
        object MaxValue { get; }

        /// <summary>
        /// Gets the name of the generated entity class property mapped to this column.
        /// </summary>
        string PropertyName { get; }

        /// <summary>
        /// Gets the value which indicates whether the value of the field is automatically generated by
        /// database (eg. timestamp or computed fields in SQL Server). 
        /// If set to true then this field's value cannot be inserted or updated.
        /// </summary>
        bool IsAutoGenerated { get; }

        /// <summary>
        /// Gets the sequence used to increment values for this field.
        /// <b>Null</b> if the column is not an auto-incremented field or if sequence is not used.
        /// </summary>
        string SequenceName { get; }

        /// <summary>Gets the collection of customized information associated with the column.</summary>
        /// <value>A IPropertyCollection with all custom information. <b>null</b> if no custom information is configured.</value>
        /// <remarks>The ExtendedProperties property lets you configure custom information for the column such as DBMS-specific properties.</remarks>
        IPropertyCollection<string> ExtendedProperties { get; }

        #endregion
    }

    /// <summary>Provides values for immutable <see cref="IDbColumn"/> properties.</summary>
    [Serializable]
    public sealed class DbColumnConfiguration : IDbColumnConfiguration
    {
        #region CTor.

        private DbColumnConfiguration()
        {
        }

        /// <summary>
        /// Initializes a new instance of the DbColumn class.
        /// </summary>
        /// <param name="columnName">Column name.</param>
        /// <param name="dbType">DB data type.</param>
        /// <param name="dataType">.NET type of data stored in the column.</param>
        /// <param name="nullable">Specifies whether the values of this column are nullable.</param>
        /// <param name="ordinal">Column's ordinal in parent table.</param>
        /// <param name="autoIncrement">Specifies whether the values of this column are automatically incremented.</param>
        /// <param name="defaultValue">Default value.</param>
        /// <param name="maxLengthIfText">The maximum length of a text column.</param>
        /// <param name="isPrimaryKeyPart">Indicates whether the column is a part of the primary key.</param>
        /// <param name="isForeignKeyPart">Indicates whether the column is a part of a foreign key.</param>
        /// <param name="isUniqueConstraintPart">Indicates whether the column is a part of a unique constraint.</param>
        /// <param name="propertyName">Name of the class property mapped to this column.</param>		
        /// <param name="minValue">The smallest possible value of this column. May be <b>null</b>.</param>
        /// <param name="maxValue">The smallest possible value of this column. May be <b>null</b>.</param>
        /// <param name="isAutoGenerated">Indicates whether the value of the field is automatically generated by database (eg. timestamp in SQL Server).</param>
        /// <param name="sequenceName">Sequence that increments value for this field. <b>Null</b> if the field is not auto-incremented or sequence does not exist.</param>
        public DbColumnConfiguration(string columnName, DbType dbType, Type dataType, bool nullable, int ordinal, bool autoIncrement, object defaultValue, 
            int maxLengthIfText, bool isPrimaryKeyPart, bool isForeignKeyPart, bool isUniqueConstraintPart, string propertyName, object minValue, 
            object maxValue, bool isAutoGenerated, string sequenceName)
        {
            this.ColumnName = columnName;
            this.DbType = dbType;
            this.DataType = dataType;
            this.IsNullable = nullable;
            this.Ordinal = ordinal;
            this.AutoIncrement = autoIncrement;
            this.DefaultValue = defaultValue;
            this.MaxLengthIfText = maxLengthIfText;
            this.IsPrimaryKeyPart = isPrimaryKeyPart;
            this.IsForeignKeyPart = isForeignKeyPart;
            this.IsUniqueConstraintPart = isUniqueConstraintPart;
            this.PropertyName = propertyName;
            this.MinValue = minValue;
            this.MaxValue = maxValue;
            this.IsAutoGenerated = isAutoGenerated;
            this.SequenceName = sequenceName;
            this.ExtendedProperties = null;
        }

        /// <summary>
        /// Initializes a new instance of the DbColumn class.
        /// </summary>
        /// <param name="columnName">Column name.</param>
        /// <param name="dbType">DB data type.</param>
        /// <param name="dataType">.NET type of data stored in the column.</param>
        /// <param name="nullable">Specifies whether the values of this column are nullable.</param>
        /// <param name="ordinal">Column's ordinal in parent table.</param>
        /// <param name="autoIncrement">Specifies whether the values of this column are automatically incremented.</param>
        /// <param name="defaultValue">Default value.</param>
        /// <param name="maxLengthIfText">The maximum length of a text column.</param>
        /// <param name="isPrimaryKeyPart">Indicates whether the column is a part of the primary key.</param>
        /// <param name="isForeignKeyPart">Indicates whether the column is a part of a foreign key.</param>
        /// <param name="isUniqueConstraintPart">Indicates whether the column is a part of a unique constraint.</param>
        /// <param name="propertyName">Name of the class property mapped to this column.</param>		
        /// <param name="minValue">The smallest possible value of this column. May be <b>null</b>.</param>
        /// <param name="maxValue">The smallest possible value of this column. May be <b>null</b>.</param>
        /// <param name="isAutoGenerated">Indicates whether the value of the field is automatically generated by database (eg. timestamp in SQL Server).</param>
        /// <param name="sequenceName">Sequence that increments value for this field. <b>Null</b> if the field is not auto-incremented or sequence does not exist.</param>
        /// <param name="extendedProperties">Customized information associated with the table.</param>
        public DbColumnConfiguration(string columnName, DbType dbType, Type dataType, bool nullable, int ordinal, bool autoIncrement, object defaultValue,
            int maxLengthIfText, bool isPrimaryKeyPart, bool isForeignKeyPart, bool isUniqueConstraintPart, string propertyName, object minValue,
            object maxValue, bool isAutoGenerated, string sequenceName, IPropertyCollection<string> extendedProperties)
        {
            this.ColumnName = columnName;
            this.DbType = dbType;
            this.DataType = dataType;
            this.IsNullable = nullable;
            this.Ordinal = ordinal;
            this.AutoIncrement = autoIncrement;
            this.DefaultValue = defaultValue;
            this.MaxLengthIfText = maxLengthIfText;
            this.IsPrimaryKeyPart = isPrimaryKeyPart;
            this.IsForeignKeyPart = isForeignKeyPart;
            this.IsUniqueConstraintPart = isUniqueConstraintPart;
            this.PropertyName = propertyName;
            this.MinValue = minValue;
            this.MaxValue = maxValue;
            this.IsAutoGenerated = isAutoGenerated;
            this.SequenceName = sequenceName;
            this.ExtendedProperties = extendedProperties;
        }

        #endregion

        #region Properties.

        /// <summary>
        /// Gets the <see cref="DbType"/> of the column.
        /// </summary>
        public DbType DbType { get; private set; }

        /// <summary>
        /// Gets the value that indicates whether null values are allowed in this column.
        /// </summary>
        public bool IsNullable { get; private set; }

        /// <summary>
        /// Gets the value that indicates whether the column automatically increments the value for new rows added to the table.
        /// </summary>
        public bool AutoIncrement { get; private set; }

        /// <summary>
        /// Gets the name of the column.
        /// </summary>
        public string ColumnName { get; private set; }

        /// <summary>
        /// Gets .NET type of data stored in the column.
        /// </summary>
        public Type DataType { get; private set; }

        /// <summary>
        /// Gets the default value for the column when creating new rows.
        /// </summary>
        public object DefaultValue { get; private set; }

        /// <summary>
        /// Gets the maximum length of a text column.
        /// Has no effect it it is not a text column.
        /// </summary>
        public int MaxLengthIfText { get; private set; }

        /// <summary>
        /// Gets the position of the column in the database table/view.
        /// </summary>
        public int Ordinal { get; private set; }

        /// <summary>
        /// Gets the value that indicates whether the column is a part of the primary key.
        /// </summary>
        public bool IsPrimaryKeyPart { get; private set; }

        /// <summary>
        /// Gets the value that indicates whether the column is a part of a foreign key.
        /// </summary>
        public bool IsForeignKeyPart { get; private set; }

        /// <summary>
        /// Gets the value that indicates whether the column is a part of a unique constraint.
        /// </summary>
        public bool IsUniqueConstraintPart { get; private set; }

        /// <summary>
        /// Gets the smallest possible value of this column.
        /// </summary>
        public object MinValue { get; private set; }

        /// <summary>
        /// Gets the smallest possible value of this column.
        /// </summary>
        public object MaxValue { get; private set; }

        /// <summary>
        /// Gets the name of the generated entity class property mapped to this column.
        /// </summary>
        public string PropertyName { get; private set; }

        /// <summary>
        /// Gets the value which indicates whether the value of the field is automatically generated by
        /// database (eg. timestamp or computed fields in SQL Server). 
        /// If set to true then this field's value cannot be inserted or updated.
        /// </summary>
        public bool IsAutoGenerated { get; private set; }

        /// <summary>
        /// Gets the sequence used to increment values for this field.
        /// <b>Null</b> if the column is not an auto-incremented field or if sequence is not used.
        /// </summary>
        public string SequenceName { get; private set; }

        /// <summary>Gets the collection of customized information associated with the column.</summary>
        /// <value>A IPropertyCollection with all custom information. <b>null</b> if no custom information is configured.</value>
        /// <remarks>The ExtendedProperties property lets you configure custom information for the column such as DBMS-specific properties.</remarks>
        public IPropertyCollection<string> ExtendedProperties { get; private set; }

        #endregion
    }
}